home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 June: Reference Library / Dev.CD Jun 99 RL Disk 1.toast / Technical Documentation / Develop / develop Issue 28 / develop Issue 28 code / Sketch / Source / AppleEvent / AERCoreSuite.c next >
Encoding:
C/C++ Source or Header  |  1996-08-25  |  13.1 KB  |  468 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2.  * 
  3.  * AERCoreSuite.c
  4.  * 
  5.  * AppleEvent Registry (AER) Core suite support
  6.  *
  7.  ****************************************************************************/
  8.  
  9. #include <string.h>        // for memset()
  10.  
  11. #include "AERCoreSuite.h"
  12.  
  13. #include "AppleEvent.h"
  14.  
  15. // dispatch core events to objects of the appropriate object type
  16.  
  17. #include "OSLClassApplication.h"
  18. #include "OSLClassDocument.h"
  19. #include "OSLClassWindow.h"
  20. #include "OSLClassGraphicObject.h"
  21.  
  22. #include "OSLHelpers.h"
  23.  
  24. /* ============================================================================
  25.     Theory of Operation:
  26.     
  27.     The Core Suite is handled using the "object-first" method, described in 
  28.     Richard Clark's article in develop: "Apple Event Objects and You"
  29.     
  30.     The short story is that we install a single event handler to receive all 
  31.     events from the kAECoreSuite class of the Core Suite. There are object accessors 
  32.     for each class that is defined in the Core Suite, including Application, Document,
  33.     GraphicObject, and Window.
  34.     
  35.     The AECoreSuiteEventHandler event handler is installed with a typeWildCard event ID
  36.     so that all events in the Core suite, except Make (CreateElement) are passed to it.
  37.     Make has its own handler because it doesn't receive its ospec in the direct
  38.     parameter, unlike all the other events. 
  39.     
  40.     AECoreSuiteEventHandler first calls AEResolve() to find out what type of object 
  41.     is in the direct parameter and to resolve a token for that object.
  42.     
  43.     AECoreSuiteEventHandler then passes the token, the original event, and the reply on to
  44.     the event dispatcher for the type of object found in the direct parameter. 
  45.     Each object's event dispatcher then extracts the eventID from the apple event and 
  46.     passes the token on to the object's handler for that event. The handler for the 
  47.     object/event combination does the real work of manipulating the program's data and 
  48.     stuffs the result into the reply parameter.
  49.     
  50.  ============================================================================ */
  51.  
  52.  extern pascal OSErr AEObjectInit(void);
  53.  
  54. static pascal OSErr     AECoreSuiteEventHandler            (AppleEvent *message, AppleEvent *reply, long refcon);
  55. static pascal OSErr     AECreateElementEventHandler    (AppleEvent *message, AppleEvent *reply, long refcon);
  56.  
  57. // ---------------------------------------------------------------------------------------
  58.  
  59. void
  60. InitCoreTokenRecord(CoreTokenRecord *token)
  61. {
  62.     memset(token, '\0', sizeof(CoreTokenRecord));
  63.     token->propertyCode = typeNull;
  64. }
  65.  
  66. /*****************************************************************************
  67.  * 
  68.  * InstallCoreSuiteHandlers()
  69.  * 
  70.  * The event handler gets ALL events for the core suite
  71.  *
  72.  * The accessor functions are used by AEResolve() to construct tokens
  73.  * for the object in the direct parameter of the core suite events.
  74.  *
  75.  *****************************************************************************/
  76.  
  77. Boolean
  78. InstallCoreSuiteHandlers(void)
  79. {
  80.     Boolean error = AEObjectInit() ;
  81.     
  82.     // Install event handlers for all StandardSuite (kAECoreSuite) events except Make (CreateElement)
  83.     
  84.     if (error == noErr) 
  85.         error = AEInstallEventHandler(kAECoreSuite, 
  86.                                                 typeWildCard, 
  87.                                                 NewAEEventHandlerProc(AECoreSuiteEventHandler), 
  88.                                                 0, 
  89.                                                 false);
  90.  
  91.     // Special handler for StandardSuite Make (CreateElement) event
  92.     
  93.     if (error == noErr) 
  94.         error = AEInstallEventHandler(kAECoreSuite, 
  95.                                                 kAECreateElement, 
  96.                                                 NewAEEventHandlerProc(AECreateElementEventHandler), 
  97.                                                 0, 
  98.                                                 false);
  99.     
  100.     // Install object accessors for each class we support
  101.     
  102.     if (error == noErr) 
  103.         error = InstallApplicationAccessors();        // Application
  104.     
  105.     if (error == noErr) 
  106.         error = InstallDocumentAccessors();            // Document
  107.         
  108.     if (error == noErr) 
  109.         error = InstallWindowAccessors();                // Window
  110.         
  111.     if (error == noErr) 
  112.         error = InstallGraphicObjectAccessors();    // Graphic Object
  113.         
  114.     // Install a generic handler to get a property from a typeAEList of tokens
  115.  
  116.     if (error == noErr) 
  117.         error = AEInstallObjectAccessor(cProperty, typeAEList, NewOSLAccessorProc(PropertyTokenFromAEListOfTokens), 0L, false);    
  118.     
  119.     return (error == noErr);
  120. }
  121.  
  122. // ---------------------------------------------------------------------------------------
  123. // This handler receives ALL core suite events EXCEPT Make (CreateElement)
  124. // and passes them on to the correct object dispatcher:
  125. //    cApplication, cDocument, cFile, cGraphicObject, and cWindow.
  126. // Make (CreateElement) is different because it passes its ospec in the
  127. // insertionLoc parameter instead of in the direct object parameter.
  128.  
  129. static pascal OSErr
  130. AECoreSuiteEventHandler(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  131. {
  132.     OSErr        error              = noErr;
  133.     OSErr        ignoreError;
  134.     OSErr        eventError           = noErr;
  135.  
  136.     Boolean  objectResolved  = true;
  137.     
  138.     AEDesc    directParameter = {typeNull, nil};    // this is a ospec for the core suite
  139.     AEDesc    token                 = {typeNull, nil};    // this is filled in by AEResolve()
  140.  
  141.     DescType tokenType        = typeNull;
  142.     DescType dispatchClass  = typeNull;
  143.     
  144.     long        numItems;
  145.     
  146.     // extract the direct parameter (an object specifier)
  147.     
  148.     error = AEGetKeyDesc(appleEvent, 
  149.                                 keyDirectObject, 
  150.                                 typeWildCard, 
  151.                               &directParameter);
  152.     if (error != noErr)
  153.         goto CleanUp;
  154.     
  155.     // check for null descriptor, which AEResolve doesn't handle well
  156.     // If it's not null, then AEResolve will return an application-defined token
  157.     
  158.     if (directParameter.descriptorType == typeNull) 
  159.     {
  160.         token = directParameter;
  161.     }
  162.     else {
  163.         // The direct parameter contains an object specifier, or an "reference" in
  164.         // AppleScript terminology, such as "rectangle 1 of document 1". 
  165.         // AEResolve() will recursively call our installed object accessors
  166.         // until it returns a token with data referencing the requested object.
  167.          
  168.         error = AEResolve(&directParameter, kAEIDoMinimum, &token);
  169.         
  170.     }
  171.     
  172.     if (error == errAENoSuchObject || error == errAEIllegalIndex)
  173.     {
  174.         // If we were executing an "Exists..." appleevent, we can reply it here
  175.         // because we have already determined that it DOES NOT exist.
  176.         // First, we get the event ID. We use "eventError" instead of "error"
  177.         // so that the result of AEGetAttributePtr() does not disturb the
  178.         // errAENoSuchObject result previously returned.
  179.         
  180.         AEEventID    eventID;
  181.         OSType        typeCode;
  182.         Size            actualSize = 0L;        
  183.         eventError = AEGetAttributePtr(appleEvent, 
  184.                                                    keyEventIDAttr, 
  185.                                                    typeType, 
  186.                                                    &typeCode, 
  187.                                                    (Ptr)&eventID,     // Get the eventID from the AppleEvent
  188.                                                    sizeof(eventID), 
  189.                                                    &actualSize);
  190.                                           
  191.         // If event was an "Exists..." message, store the result (false) in the reply
  192.         // because AEResolve() returned errAENoSuchObject.
  193.         
  194.         if (eventError == noErr && eventID == kAEDoObjectsExist)
  195.         {
  196.             Boolean foundIt = false;
  197.             ignoreError = AEPutParamPtr(reply, keyAEResult, typeBoolean, (Ptr)&foundIt, sizeof(Boolean));
  198.             
  199.             // Now, we set the error to noErr so that the scripting component doesn't complain
  200.             // that the object does not exist. We only do this if we were executing an "Exists..."
  201.             // event. Otherwise, the errAENoSuchObject will be returned.
  202.             error = noErr;
  203.         }
  204.         
  205.         objectResolved = false;
  206.     }
  207.  
  208.     if (objectResolved == false || error != noErr)
  209.         goto CleanUp;
  210.  
  211.     // Pass the token returned by AEResolve(), and the original AppleEvent event and reply,
  212.     // on to the appropriate object dispatcher
  213.  
  214.     // The token type is, by convention, the same as class ID that handles this event.
  215.     // However, for property tokens, tokenType is cProperty for all objects, so
  216.     // we look inside the token at its dispatchClass to find out which class of object
  217.     // should really handle this AppleEvent.
  218.     
  219.     // Also, if the resolver returned a list of objects in the token, 
  220.     // the type will be typeAEList or one of our special list types, so
  221.     // we set the dispatch class based on the list type
  222.     // instead of on the type of the token itself
  223.     
  224.     if (TokenContainsTokenList(&token))
  225.     {
  226.         error = AECountItems(&token, &numItems);
  227.         
  228.         if (numItems == 0)    // could be an empty list
  229.         {
  230.             dispatchClass = typeNull;
  231.         }
  232.         else
  233.         {
  234.             AEDesc tempToken = {typeNull, nil};
  235.             error = GetFirstNonListToken((AEDesc *)&token, &tempToken);
  236.             if (error == noErr && tempToken.descriptorType != typeNull)
  237.             {
  238.                 dispatchClass = ExtractDispatchClassFromToken(&tempToken);
  239.             }
  240.             else
  241.             {
  242.                 dispatchClass = typeNull;
  243.                 error = noErr;
  244.             }
  245.             AEDisposeDesc(&tempToken);
  246.         }
  247.     }
  248.     else if (token.descriptorType == typeNull)               // make sure we correctly handle things for cApplication that don't have a direct parameter
  249.     {
  250.         dispatchClass = typeNull;
  251.     }
  252.     else
  253.     {
  254.         dispatchClass = ExtractDispatchClassFromToken(&token);
  255.     }
  256.         
  257.     if (dispatchClass == cFile)
  258.     {
  259.         AEEventID    eventID    = 0L;
  260.         OSType        typeCode   = 0L;
  261.         Size            actualSize = 0L;        
  262.         eventError = AEGetAttributePtr(appleEvent, 
  263.                                                    keyEventIDAttr, 
  264.                                                    typeType, 
  265.                                                    &typeCode, 
  266.                                                    (Ptr)&eventID,     // Get the eventID from the AppleEvent
  267.                                                    sizeof(eventID), 
  268.                                                    &actualSize);                                          
  269.     }
  270.     
  271.     switch (dispatchClass) 
  272.     {
  273.     
  274.         case typeNull:
  275.         case cApplication:
  276.             error = ApplicationEventDispatcher(&token, appleEvent, reply, refcon);
  277.             break;
  278.         
  279.         case cDocument:
  280.             error = DocumentEventDispatcher(&token, appleEvent, reply, refcon);
  281.             break;
  282.         
  283.         case cWindow:
  284.             error = WindowEventDispatcher(&token, appleEvent, reply, refcon);
  285.             break;
  286.  
  287.  
  288.         // -----
  289.         // Handles all Graphic Object subclasses
  290.         
  291.         case cGraphicObject:
  292.               error = GraphicObjectEventDispatcher(&token, appleEvent, reply, refcon);
  293.               break;
  294.  
  295.         default:
  296.             error = errAEEventNotHandled;
  297.     }
  298.  
  299. CleanUp:        
  300.  
  301.     AEDisposeDesc(&directParameter);
  302.     AEDisposeDesc(&token);
  303.     
  304.     return error;
  305.     
  306. }
  307.  
  308. // ---------------------------------------------------------------------------------------
  309. // This handler receives the Core suite Make (CreateElement) event
  310. // and passes it on to the correct object dispatcher:
  311. //    cApplication, cDocument, cFile, cGraphicObject, etc.
  312. // Make (CreateElement) is different than the other events processed above
  313. // because it passes its ospec in the insertionLoc parameter instead of
  314. // in the direct object parameter.
  315.  
  316. static pascal OSErr
  317. AECreateElementEventHandler(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  318. {
  319.  
  320.     OSErr                 error            = noErr;
  321.     AEDesc             token            = {typeNull, nil};
  322.     DescType             dispatchClass    = typeNull;
  323.      
  324.      // Extract the type of object we want to create.
  325.      // We use this to call the event dispatcher for that kind of objects
  326.                                 
  327.     error = AEGetParamDesc(appleEvent,
  328.                                   keyAEObjectClass,         // class of object to create
  329.                                   typeType,
  330.                                   &token);
  331.     if (error != noErr)  
  332.         goto CleanUp;
  333.  
  334.     dispatchClass = **(DescType **)(token.dataHandle);
  335.                     
  336.     switch (dispatchClass) {
  337.     
  338.         // -----
  339.         // Application, document, and windows each have their own event dispatchers
  340.  
  341.         case typeNull:
  342.         case cApplication:
  343.             error = ApplicationEventDispatcher(&token, appleEvent, reply, refcon);
  344.             break;
  345.         
  346.         case cDocument:
  347.             error = DocumentEventDispatcher(&token, appleEvent, reply, refcon);
  348.             break;
  349.  
  350.         case cWindow:
  351.             error = WindowEventDispatcher(&token, appleEvent, reply, refcon);
  352.             break;
  353.  
  354.         // -----
  355.         // All graphic objects are handled by cGraphicObject event dispatcher
  356.  
  357.         case cGraphicLine:
  358.         case cGroupedGraphic:
  359.         case cGraphicObject:
  360.          case cOval:
  361.           case cPolygon:
  362.           case cRectangle:
  363.         case cRoundedRectangle:
  364.             error = GraphicObjectEventDispatcher(&token, appleEvent, reply, refcon);
  365.             break;
  366.  
  367.         default:
  368.             error = errAEEventNotHandled;
  369.     }
  370.  
  371. CleanUp:        
  372.  
  373.     AEDisposeDesc(&token);    
  374.     
  375.     return error;
  376.     
  377. }
  378.  
  379.  
  380. //----------------------------------------------------------------------------------
  381. // Handler to get a property from a typeAEList of tokens
  382. //----------------------------------------------------------------------------------
  383.  
  384. pascal OSErr 
  385. PropertyTokenFromAEListOfTokens(    DescType        desiredClass,
  386.                                      const AEDesc*        containerToken,
  387.                                              DescType        containerClass,
  388.                                              DescType        keyForm,
  389.                                     const AEDesc*        keyData,
  390.                                              AEDesc*        resultToken,
  391.                                              long             refCon)
  392. {
  393.     OSErr    error = noErr;
  394.     
  395.     switch (containerClass)
  396.     {            
  397.         case cGraphicObject:
  398.         case cOval:
  399.         case cPolygon:
  400.         case cRectangle:
  401.         case cRoundedRectangle:
  402.         case cGraphicLine:
  403.         case cGroupedGraphic:
  404.             error = PropertyFromGraphicObjectAccessor(desiredClass,
  405.                                                                   containerToken,
  406.                                                                   containerClass,
  407.                                                                   keyForm,
  408.                                                                   keyData,
  409.                                                                  resultToken,
  410.                                                                  refCon);
  411.             break;
  412.         
  413.  
  414.         case cWindow:
  415.             error = PropertyFromWindowAccessor(desiredClass,
  416.                                                     containerToken,
  417.                                                     containerClass,
  418.                                                     keyForm,
  419.                                                     keyData,
  420.                                                     resultToken,
  421.                                                     refCon);
  422.             break;
  423.         
  424.  
  425.         case cDocument:
  426.             error = PropertyFromDocumentAccessor(desiredClass,
  427.                                                         containerToken,
  428.                                                         containerClass,
  429.                                                         keyForm,
  430.                                                         keyData,
  431.                                                         resultToken,
  432.                                                         refCon);
  433.             break;
  434.         
  435.  
  436.         // ••• ADD OTHER CLASSES HERE, FOR COMPLETNESS
  437.         // •••
  438.         
  439.         default:
  440.             error = errAEEventNotHandled;
  441.             break;
  442.     }
  443.     
  444.     return error;
  445. }
  446.  
  447. // ---------------------------------------------------------------------------------------
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.